package com.api.user.service.impl;

import com.api.base.dao.UserMapper;
import com.api.base.model.User;
import com.api.base.service.UserService;
import com.api.common.mybatis.ResultMap;
import com.api.user.config.Ipay88;
import com.api.user.config.SubscribeList;
import com.api.user.dao.PackageCoinMapper;
import com.api.user.dao.RechargeOrderMapper;
import com.api.user.dao.ReferralLogMapper;
import com.api.user.dao.UserInfoMapper;
import com.api.user.enums.IdentificationStatusEnums;
import com.api.user.model.*;
import com.api.user.service.CoinTransactionService;
import com.api.user.service.PaymentOrderService;
import com.api.user.service.PointsTransactionService;
import com.api.user.service.RechargeOrderService;
import com.api.core.service.AbstractService;
import com.api.user.vo.SubscribeVo;
import org.apache.commons.lang3.time.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.api.common.JSONUtils;
import com.api.core.response.Result;
import com.api.core.response.ResultGenerator;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

/**
 * Created by wanghuiwen on 2021/04/08.
 */
@Service
@Transactional
public class RechargeOrderServiceImpl extends AbstractService<RechargeOrder> implements RechargeOrderService {

    Logger logger  = LoggerFactory.getLogger(this.getClass());
    @Resource
    private RechargeOrderMapper rechargeOrderMapper;
    @Resource
    private PackageCoinMapper packageCoinMapper;
    @Resource
    private UserInfoMapper userInfoMapper;
    @Resource
    private CoinTransactionService coinTransactionService;

    @Value("${ipay88.merchant.code}")
    private String merchantCode;
    @Value("${ipay88.merchant.key}")
    private String merchantKey;

    @Value("${ipay88.merchant.responseURL}")
    private String responseURL;

    @Value("${ipay88.merchant.backendURL}")
    private String backendURL;

    @Value("${ipay88.merchant.requestUrl}")
    private String requestUrl;


    @Resource
    private PaymentOrderService paymentOrderService;

    @Resource
    private SubscribeList subscribeList;
    @Resource
    private PointsTransactionService pointsTransactionService;

    @Resource
    private UserMapper userMapper;

    @Resource
    private ReferralLogMapper referralLogMapper;

    @Override
    public Result list(Map<String, Object> params, String order, Integer page, Integer size) {
        Map<String, Object> orderParams = JSONUtils.json2map(order);
        for (String key : orderParams.keySet()) {
            if (orderParams.get(key) != null && orderParams.get(key).equals("ascending")) orderParams.put(key, "asc");
            if (orderParams.get(key) != null && orderParams.get(key).equals("descending")) orderParams.put(key, "desc");
        }
        orderParams.put("id", "desc");
        PageHelper.startPage(page, size);
        List<Map<String, Object>> res = rechargeOrderMapper.list(params, orderParams);
        PageInfo<Map<String, Object>> pageInfo = new PageInfo<>(res);
        List<Map<String, Object>> statistics = rechargeOrderMapper.statistics(params);

        Map<String, Object> result = new HashMap<>();
        result.put("list", pageInfo);
        result.put("statistics", statistics);
        return ResultGenerator.genSuccessResult(result);
    }

    @Override
    public Result add(Long packageId, Long userId) {
        UserInfo userInfo = userInfoMapper.selectByPrimaryKey(userId);
        PackageCoin packageCoin = packageCoinMapper.selectByPrimaryKey(packageId);
        RechargeOrder order = new RechargeOrder();
        order.setPackageId(packageId);
        order.setCreateTime(new Date().getTime());
        order.setState(1);
        order.setTotalAmount(packageCoin.getCoin().add(packageCoin.getDiscount()));
        order.setUserId(userId);
        save(order);

        PaymentOrder paymentOrder = new PaymentOrder();
        paymentOrder.setAmount(packageCoin.getRm());
        paymentOrder.setCreateDate(new Date().getTime());
        paymentOrder.setCurrency("MYR");
        paymentOrder.setOrderId(order.getId());
        paymentOrder.setOrderType(1);
        paymentOrder.setUserId(userId);
        paymentOrder.setStatus(1);
        paymentOrderService.save(paymentOrder);

        Map<String, Object> map = new HashMap<>();
        map.put("requestUrl", requestUrl);
        map.put("MerchantCode", merchantCode);
        map.put("ResponseURL", responseURL);
        map.put("BackendURL", backendURL);
        map.put("PaymentId", "");
        map.put("RefNo", paymentOrder.getId());
        map.put("Amount", packageCoin.getRm().toString());
        map.put("Currency", "MYR");
        map.put("ProdDesc", "RechargeOrder");
        map.put("UserName", userInfo.getFullName());
        map.put("UserEmail", userInfo.getEmail());
        map.put("UserContact", userInfo.getPhoneNumber());
        map.put("Remark", "RechargeOrder");
        map.put("Lang", "UTF-8");
        map.put("SignatureType", "SHA256");
        map.put("Signature", Ipay88.Signature(paymentOrder.getId().toString(), packageCoin.getRm().toString(), "MYR", merchantKey, merchantCode));
        return ResultGenerator.genSuccessResult(map);
    }

    @Override
    public Result topup(Long userId, Integer coin) {

        RechargeOrder order = new RechargeOrder();
        order.setCreateTime(new Date().getTime());
        order.setState(3);
        order.setTotalAmount(new BigDecimal(coin));
        order.setUserId(userId);
        save(order);

        // 添加交易记录 扣除费用
        CoinTransaction transaction = new CoinTransaction();
        transaction.setAmountBalance(new BigDecimal(coin));
        transaction.setOrderId(order.getId());
        transaction.setRemark("Admin top Up");
        transaction.setTransactionTime(new Date().getTime());
        transaction.setTransactionType(1);
        transaction.setToUserId(userId);
        transaction.setCreateId(1L);
        coinTransactionService.addOrSub(transaction);
        return ResultGenerator.genSuccessResult();
    }

    @Override
    public List<ResultMap<String, Object>> analysis(Integer type) {
        return rechargeOrderMapper.analysis(type);
    }

    @Override
    public List<ResultMap<String, Object>> dayAnalysis() {
        return rechargeOrderMapper.dayAnalysis();
    }

    @Override
    public List<ResultMap<String, Object>> hourAnalysis() {
        return rechargeOrderMapper.hourAnalysis();
    }

    @Override
    public String callback(String merchantCode, String paymentId, String refNo, String amount, String currency, String remark, String transId, String authCode, String status, String errDesc, String signature, String ccName, String ccNo, String s_bankname, String s_country) {
        PaymentOrder order = paymentOrderService.findById(refNo);
        logger.info("payment callback merchantCode : {}, paymentId:{}, refNo:{}, amount:{}, currency:{}, remark:{}, transId:{}, authCode:{}, status:{}, errDesc:{}, signature:{}, ccName:{}, ccNo:{}, s_bankname:{}, s_country:{}" ,
                merchantCode,paymentId,refNo,amount,currency,remark,transId,authCode,status,errDesc,signature,ccName,ccNo,s_bankname,s_country);
        if (order.getStatus() == 2 || !status.equals("1")) {
            return "RECEIVEOK";
        }
        order.setStatus(2);
        order.setCcName(ccName);
        order.setBankName(s_bankname);
        order.setCcNo(ccNo);
        paymentOrderService.update(order);

        User user = userMapper.selectByPrimaryKey(order.getUserId());

        if (order.getOrderType() == 1) {
            // 添加交易记录 扣除费用
            RechargeOrder rechargeOrder = findById(order.getOrderId());
            rechargeOrder.setState(2);
            rechargeOrderMapper.updateByPrimaryKeySelective(rechargeOrder);
            /**
             * 邀请结算
             */
            if(user.getReferralId()!=null){
                BigDecimal referralAmount =  rechargeOrder.getTotalAmount().multiply(new BigDecimal("0.05"));
                ReferralLog referralLog = new ReferralLog();
                referralLog.setReferralUser(user.getReferralId());
                referralLog.setToUser(user.getId());
                referralLog.setAmount(referralAmount);
                referralLog.setOrderId(order.getOrderId());
                referralLog.setrAmount(referralAmount);
                referralLogMapper.insert(referralLog);

                CoinTransaction transaction = new CoinTransaction();
                transaction.setAmountBalance(referralAmount);
                transaction.setOrderId(referralLog.getReferralLogId());
                transaction.setRemark("Referral");
                transaction.setTransactionTime(new Date().getTime());
                transaction.setTransactionType(8);
                transaction.setToUserId(user.getReferralId());
                transaction.setCreateId(order.getUserId());
                coinTransactionService.addOrSub(transaction);

                CoinTransaction userTransaction = new CoinTransaction();
                userTransaction.setAmountBalance(referralAmount);
                userTransaction.setOrderId(referralLog.getReferralLogId());
                userTransaction.setRemark("Referral");
                userTransaction.setTransactionTime(new Date().getTime());
                userTransaction.setTransactionType(8);
                userTransaction.setToUserId(user.getId());
                userTransaction.setCreateId(order.getUserId());
                coinTransactionService.addOrSub(userTransaction);
            }

            CoinTransaction transaction = new CoinTransaction();
            transaction.setAmountBalance(rechargeOrder.getTotalAmount());
            transaction.setOrderId(order.getOrderId());
            transaction.setRemark("Top Up");
            transaction.setTransactionTime(new Date().getTime());
            transaction.setTransactionType(1);
            transaction.setToUserId(order.getUserId());
            transaction.setCreateId(order.getUserId());
            coinTransactionService.addOrSub(transaction);
        }

        if (order.getOrderType() == 2) {
            SubscribeVo subscribeVo = subscribeList.getSubscribeVos().stream().filter(vo -> vo.getId() == order.getOrderId()).findFirst().orElse(null);
            UserInfo info = userInfoMapper.selectByPrimaryKey(order.getUserId());
            info.setVipLevel(IdentificationStatusEnums.USER_LEVEL_PRO);
            info.setVipExpireTime(DateUtils.addMonths(new Date(), subscribeVo.getMonth()).getTime());
            userInfoMapper.updateByPrimaryKeySelective(info);

            CoinTransaction transaction = new CoinTransaction();
            transaction.setAmountBalance(new BigDecimal(subscribeVo.getCoins()));
            transaction.setOrderId(order.getOrderId());
            transaction.setRemark("Subscribe Bonus");
            transaction.setTransactionTime(new Date().getTime());
            transaction.setTransactionType(1);
            transaction.setToUserId(order.getUserId());
            transaction.setCreateId(order.getUserId());
            coinTransactionService.addOrSub(transaction);

            PointsTransaction pointsTransaction = new PointsTransaction();
            pointsTransaction.setToUserId(order.getUserId());
            pointsTransaction.setRemark("Subscribe Bonus");
            pointsTransaction.setTransactionTime(new Date().getTime());
            pointsTransaction.setTransactionType(8);
            pointsTransaction.setPointAmount(new BigDecimal(subscribeVo.getPoints()));
            pointsTransaction.setOrderId(0L);
            pointsTransaction.setCreateId(order.getUserId());
            pointsTransactionService.addOrSub(pointsTransaction);

        }
        return "RECEIVEOK";
    }

    public static void main(String[] args) {

        RestTemplate  restTemplate = new RestTemplate();
        String url = "https://payment.ipay88.com.my/epayment/entry.asp";
        MultiValueMap<String,Object> map= new LinkedMultiValueMap<>();
        map.add("MerchantCode","M35397");
        map.add("PaymentId","");
        map.add("RefNo","115");
        map.add("Amount","1.00");
        map.add("Currency","MYR");
        map.add("ProdDesc","RechargeOrder");
        map.add("UserName","test124");
        map.add("UserEmail","test124@gmail.com");
        map.add("UserContact","18235404640");
        map.add("Remark","RechargeOrder");
        map.add("Lang","UTF-8");
        map.add("SignatureType","SHA256");
        map.add("ResponseURL","https://user.bountee.com.my/");
        map.add("BackendURL","http://api.bountee.com.my/api/recharge/order/payment/callback");
        map.add("Signature","8cb8dd45964bf47e05cfbccbd60f9bd0ff4ba4684bb1ae33964054a83236bb49");

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        headers.add("Referer","https://bountee.com.my/");
        headers.add("REFERER","https://bountee.com.my/");
        HttpEntity<MultiValueMap<String,Object>> request = new HttpEntity<>(map, headers);
        ResponseEntity responseEntity =  restTemplate.postForEntity(url, request,String.class);
        System.out.println(responseEntity);
    }
}